講到 SPA(single page application)與傳統網頁的差異,應該很多人會想到傳統網頁跳頁往往會有一段載入時間,導致畫面空白,讓使用者需要對著電腦螢幕發呆吧。
而 SPA 的出現大大改善了 web 應用的使用者體驗,切換頁面可以在一瞬間達成,今天就要來介紹在 react 中切換路由的神器 - React router。
React router 使我們可以選擇在切換路由時要切換的元件,例如一個應用可能每一頁都會有 Navbar ,過往的作法可能是每頁中都會放置同一個 Navbar 的 template ,切換頁面時儘管 Navbar 沒有改變,還是會重新渲染。然而透過 React router 我們可以控制需要切換的元件(component),減少重複渲染,提升應用效能。
首先要先安裝相關套件
npm i react-router
npm i react-router-dom
還記得前幾天以來我們做了一個 counter 元件跟一個 form 元件嗎?
今天就簡單實現可以在兩個組件中做切換
會有兩個 link ,分別切換到對應的路由
表單填答送出後會自動切換回 counter page
(可能不是很有意義的應用程式,但的確對了解 router 非常有幫助)
開始囉!
在 App.js 中引入以下套件
import { BrowserRouter as Router, Switch, Route, Link } from 'react-router-dom';
接著改變 App.js 的程式碼
const App = () => {
const [count, setCount] = useState(0);
const [formDone, setFormDone] = useState(false)
return (
<Router>
<div className="App">
<p>react router example</p>
<ul>
<li><Link to="counter">Counter</Link></li>
<li><Link to="form">Form</Link></li>
</ul>
<Switch>
<Route path='/counter' component={Counter}/>
<Route path='/form' component={Form}/>
/>
</Switch>
</div>
</Router>
);
}
<a>
tag ,用來導引到不同路由,to 對應的是 Route 中定義的路由比較重要的就是 Route 了,在這可以定義 URL路由(path),還可以定義該路由要顯示的 component。
比較細心的讀者應該會發現一個問題:
之前的範例中, counter 跟 form 都有傳 props 下去欸,但是這邊看起來沒有辦法傳 props 欸!
如果要傳 props 給 router 中的 component,需要改寫成以下程式
<Route path='/counter' component={() => <Counter count={count} setCount={setCount}/>}/>
<Route path='/form' component={() => <Form formDone={formDone} setFormDone={setFormDone}/>}/>
這時 router 就設置完成了,網頁雖然很陽春,卻有了 router 的功能。
counter 跟 form 的 link 因為放在 swich 外,因此不管切到哪個路由都會存在,點擊它們會在下面顯示相對應的 component。
最後來實作一個功能,有時候我們不想要都需要點擊 link 才能跳頁,像這個範例也許我們希望在送出表單後自動跳到 counter 頁面。
我們可以透過 history 達到這個功能
Form.js中
import React,{ useState } from 'react'
import { withRouter } from "react-router";
const Form = (props) => {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const handleSubmit = (e) => {
e.preventDefault();
props.setFormDone(true);
setEmail('');
setPassword('');
props.history.push('/counter');
}
return (
<div>
<form onSubmit={handleSubmit}>
<input name="email" type="text" onChange={(e) => setEmail(e.target.value)} value={email} />
<input name="password" type="password" onChange={(e) => setPassword(e.target.value)} value={password} />
<input type="submit" value="submit" />
</form>
{props.formDone ? "成功填寫表單" : "表單未完成"}
</div>
)
}
export default withRouter(Form);
要使用這個功能,首先從 react-router 引入 withRouter,它是一個 higher-order-component(HOC),不了解的讀者建議可以去了解一下,簡單來說就是使用它包住原先的 component 後,可以賦予 component 一些它提供的功能。
而 withRouter 提供的是 history 這個 props
在 handleSubmit 的最後呼叫了 props.history.push('/counter')
這會自動把你的路由“推動”到 counter 的 router,因此就達到送出表單後自動跳頁的功能了。
history 還有提供其他種函式可以使用,就交給讀者自行研究囉~
有了 router 之後,在搭配前幾天學習的概念,其實已經可以做出非常多應用了,從明天開始會進入比較進階的概念 - state management,明天見。
您好,我再App.js import react-router-dom後,出現下列錯誤
這個解決了,版本問題,將Switch > Routes
withRouter目前也被取代了,可參考以下:
import { useState } from "react";
import { useNavigate } from 'react-router-dom';
const Form = (prop) => {
const navigate = useNavigate();
//...
const handleSubmit = (e) => {
e.preventDefault(); //阻止事件的預設行為
navigate('/counter');
}
return (
//...
)
}
export default Form;